package main

import (
	"encoding/json"
	"fmt"
	"github.com/wuzfei/go-helper/maps"
	"github.com/wuzfei/go-helper/slices"
	"hash/crc32"
	"io"
	"os"
	"sync"
	"time"
)

type pkgMap map[string]*PkgItem

type PkgList struct {
	mux     sync.RWMutex
	list    pkgMap
	file    string
	modTime time.Time
}

func NewPkgList(file string) (*PkgList, error) {
	pl := &PkgList{
		file: file,
		list: make(pkgMap),
	}
	err := pl.refreshList()
	if err != nil {
		return nil, err
	}
	return pl, nil
}

func (pl *PkgList) upgrade(params *CheckUpgradeReq) (*PkgItem, bool) {
	if pl.isModify() {
		fmt.Println("修改了文件")
		err := pl.refreshList()
		if err != nil {
			fmt.Println("重新读取pkgList失败", err)
			return nil, false
		}
	}
	pl.mux.RLock()
	defer pl.mux.RUnlock()
	key := fmt.Sprintf("%s_%s_%s", params.Env, params.Os, params.Arch)
	if pItem, ok := pl.list[key]; ok {
		//根据条件判断是否需要更新
		needUpgrade := false
		if slices.Contains(pItem.IncludeNodes, params.NodeId) {
			needUpgrade = true
		} else if slices.Contains(pItem.ExcludeNodes, params.NodeId) {
			needUpgrade = false
		} else {
			if pItem.Gray == 0 {
				needUpgrade = true
			} else {
				if int(crc32.ChecksumIEEE([]byte(params.NodeId))%100) < pItem.Gray {
					needUpgrade = true
				}
			}
		}
		//需要更新,根据版本判断是否更新
		if needUpgrade {
			fmt.Println(params.Ver.VerInt == pItem.Version.VerInt, params.Ver.VerInt, pItem.Version)
			if params.Ver.VerInt == pItem.Version.VerInt {
				fmt.Println(params.CommitId, pItem.CommitId)
				if params.CommitId != pItem.CommitId {
					return pItem, true
				}
			} else {
				if params.Ver.VerInt < pItem.Version.VerInt {
					return pItem, true
				}
			}
		}
	}
	return nil, false
}

func (pl *PkgList) latest(params *LatestReq) *PkgItem {
	if pl.isModify() {
		fmt.Println("修改了文件")
		err := pl.refreshList()
		if err != nil {
			fmt.Println("重新读取pkgList失败", err)
			return nil
		}
	}
	pl.mux.RLock()
	defer pl.mux.RUnlock()
	key := fmt.Sprintf("%s_%s_%s", params.Env, params.Os, params.Arch)
	if pItem, ok := pl.list[key]; ok {
		return pItem
	}
	return nil
}

func (pl *PkgList) release(pkg *PkgItem) error {
	pl.mux.Lock()
	defer pl.mux.Unlock()
	list := make(pkgMap)
	maps.Copy(list, pl.list)
	list[pkg.CheckKey()] = pkg
	res, err := json.Marshal(list)
	if err != nil {
		return err
	}
	fp, err := os.OpenFile(pl.file, os.O_RDWR|os.O_TRUNC, 0666)
	if err != nil {
		return err
	}
	_, err = fp.Write(res)
	if err != nil {
		return err
	}
	fs, err := fp.Stat()
	if err != nil {
		return err
	}
	pl.list = list
	pl.modTime = fs.ModTime()
	return nil
}

func (pl *PkgList) refreshList() error {
	pl.mux.Lock()
	defer pl.mux.Unlock()
	if pl.isModify() {
		fp, err := openFile(pl.file)
		if err != nil {
			return err
		}
		defer fp.Close()
		res, err := io.ReadAll(fp)
		if err != nil {
			return err
		}
		list := make(pkgMap)
		if len(res) > 0 {
			err = json.Unmarshal(res, &list)
			if err != nil {
				return err
			}
		}
		fs, err := fp.Stat()
		if err != nil {
			return err
		}
		pl.list = list
		pl.modTime = fs.ModTime()
	}
	return nil
}

func (pl *PkgList) isModify() bool {
	fi, err := os.Stat(pl.file)
	if err != nil {
		return true
	}
	return fi.ModTime() != pl.modTime
}
